import { TildeType } from './Enums';
import { BuildingModel, UnitModel } from './Model';

// 仅做提供给玩家使用的工具类
export class Tools {
    /**
     * 获取单位
     * @param units 单位列表
     * @param unitId 单位ID
     * @return unit 单位
     */
    static getUnit(units: Map<number, UnitModel>, unitId: number): UnitModel | undefined {
        return units.get(unitId);
    }

    /**
     * 获取建筑
     * @param buildings 建筑集合
     * @param buildingId 建筑ID
     */
    static getBuilding(buildings: Map<number, BuildingModel>, buildingId: number): BuildingModel | undefined {
        return buildings.get(buildingId);
    }

    /**
     * 检查单位是否在地图范围内
     * @param map 地图数据
     * @param unit 单位
     * @returns 检查结果
     */
    static getUnitByPosition(units: Map<number, UnitModel>, position: { x: number; y: number }): UnitModel | undefined {
        for (const unit of units.values()) {
            if (unit.position.x === position.x && unit.position.y === position.y) {
                return unit;
            }
        }
        return undefined;
    }

    /**
     * 检查建筑是否在地图范围内
     * @param map 地图数据
     * @param building 建筑
     * @returns 检查结果
     */
    static getBuildingByPosition(
        buildings: Map<number, BuildingModel>,
        position: { x: number; y: number }
    ): BuildingModel | undefined {
        for (const building of buildings.values()) {
            if (building.position.x === position.x && building.position.y === position.y) {
                return building;
            }
        }
        return undefined;
    }

    /**
     * 检查位置是否在地图范围内
     * @param map 地图数据
     * @param position 要检查的位置
     * @returns 检查结果
     */
    static isPositionInBounds(map: number[][], position: { x: number; y: number }): { valid: boolean; error?: string } {
        if (position.y < 0 || position.y >= map.length || position.x < 0 || position.x >= map[0].length) {
            return {
                valid: false,
                error: `位置超出地图范围 - 位置(${position.x},${position.y})不在地图范围内`,
            };
        }
        return { valid: true };
    }

    /**
     * 检查目标位置是否为空位
     * @param map 地图数据
     * @param units 单位集合
     * @param buildings 建筑集合
     * @param position 目标位置
     * @returns 检查结果
     */
    static isPositionEmpty(
        map: number[][],
        units: Map<number, UnitModel>,
        buildings: Map<number, BuildingModel>,
        position: { x: number; y: number }
    ): { valid: boolean; error?: string } {
        // 检查位置是否在地图范围内
        const boundsCheck = Tools.isPositionInBounds(map, position);
        if (!boundsCheck.valid) {
            return boundsCheck;
        }

        const tileType = map[position.y][position.x];

        // 检查目标位置是否是平地
        if (tileType !== TildeType.flat) {
            return {
                valid: false,
                error: `位置不可通行 - 位置(${position.x},${position.y})地形类型为${tileType}`,
            };
        }

        // 检查目标位置是否已经有单位
        if (Tools.getUnitByPosition(units, position)) {
            return {
                valid: false,
                error: `位置被占用 - 期望: 位置(${position.x},${position.y})为空, 实际: 已有单位(ID:${
                    Tools.getUnitByPosition(units, position)?.id
                })`,
            };
        }

        // 检查目标位置是否是建筑
        if (Tools.getBuildingByPosition(buildings, position)) {
            return {
                valid: false,
                error: `位置被占用 - 期望: 位置(${position.x},${position.y})为空, 实际: 已有建筑(ID:${
                    Tools.getBuildingByPosition(buildings, position)?.id
                })`,
            };
        }

        return { valid: true };
    }

    /**
     * 检查目标位置是否为空位或河流
     * @param map 地图数据
     * @param units 单位集合
     * @param buildings 建筑集合
     * @param position 目标位置
     * @returns 检查结果
     */
    static isPositionEmptyOrRiver(
        map: number[][],
        units: Map<number, UnitModel>,
        buildings: Map<number, BuildingModel>,
        position: { x: number; y: number }
    ): { valid: boolean; error?: string } {
        // 检查位置是否在地图范围内
        const boundsCheck = Tools.isPositionInBounds(map, position);
        if (!boundsCheck.valid) {
            return boundsCheck;
        }

        const tileType = map[position.y][position.x];

        // 检查目标位置是否是平地或河流
        if (tileType !== TildeType.flat && tileType !== TildeType.river) {
            return {
                valid: false,
                error: `位置不可通行 - 位置(${position.x},${position.y})地形类型为${tileType}`,
            };
        }

        // 检查目标位置是否已经有单位
        if (Tools.getUnitByPosition(units, position)) {
            return {
                valid: false,
                error: `位置被占用 - 期望: 位置(${position.x},${position.y})为空, 实际: 已有单位(ID:${
                    Tools.getUnitByPosition(units, position)?.id
                })`,
            };
        }

        // 检查目标位置是否是建筑
        if (Tools.getBuildingByPosition(buildings, position)) {
            return {
                valid: false,
                error: `位置被占用 - 期望: 位置(${position.x},${position.y})为空, 实际: 已有建筑(ID:${
                    Tools.getBuildingByPosition(buildings, position)?.id
                })`,
            };
        }

        return { valid: true };
    }

    /**
     * 获取两个位置之间的直线距离
     * @param pos1 位置1
     * @param pos2 位置2
     * @returns 直线距离 如果两个点不在一个坐标轴上，返回false
     */
    static getDistance(pos1: { x: number; y: number }, pos2: { x: number; y: number }): number | false {
        if (pos1.x != pos2.x && pos1.y !== pos2.y) {
            return false;
        }
        if (pos1.x === pos2.x) {
            return pos1.y - pos2.y;
        }
        if (pos1.y === pos2.y) {
            return pos1.x - pos2.x;
        }
        return 0;
    }

    /**
     * 获取指定范围内的所有单位
     * @param units 单位集合
     * @param center 中心位置
     * @param range 范围
     * @returns 范围内的单位列表
     */
    static getUnitsInRange(units: Map<number, UnitModel>, center: { x: number; y: number }, range: number): UnitModel[] {
        const result: UnitModel[] = [];
        for (const unit of units.values()) {
            let dic = Tools.getDistance(center, unit.position);
            if (dic === false) {
                continue;
            }
            if (Math.abs(dic) <= range) {
                result.push(unit);
            }
        }
        return result;
    }

    /**
     * 获取指定范围内的所有建筑
     * @param buildings 建筑集合
     * @param center 中心位置
     * @param range 范围
     * @returns 范围内的建筑列表
     */
    static getBuildingsInRange(
        buildings: Map<number, BuildingModel>,
        center: { x: number; y: number },
        range: number
    ): BuildingModel[] {
        const result: BuildingModel[] = [];
        for (const building of buildings.values()) {
            let dic = Tools.getDistance(center, building.position);
            if (dic === false) {
                continue;
            }
            if (Math.abs(dic) <= range) {
                result.push(building);
            }
        }
        return result;
    }

    /**
     * 验证移动是否有效（水平或垂直，非原地不动）
     * @param begin 开始位置
     * @param end 结束位置
     * @returns 是否为有效移动
     */
    static isValidMove(begin: { x: number; y: number }, end: { x: number; y: number }): boolean {
        const deltaX = end.x - begin.x;
        const deltaY = end.y - begin.y;

        // 检查是否为有效移动（只能水平或垂直移动，不能斜向移动）
        if (deltaX !== 0 && deltaY !== 0) {
            return false; // 斜向移动不允许
        }

        // 检查是否为原地不动
        if (deltaX === 0 && deltaY === 0) {
            return false; // 原地不动不算移动
        }

        return true;
    }

    /**
     * 检查两个位置之间是否可以移动
     * @param map 地图数据
     * @param units 单位集合
     * @param buildings 建筑集合
     * @param begin 开始位置
     * @param end 结束位置
     * @returns 是否可以移动
     */
    static checkCanMove(
        map: number[][],
        units: Map<number, UnitModel>,
        buildings: Map<number, BuildingModel>,
        begin: { x: number; y: number },
        end: { x: number; y: number }
    ): boolean {
        // 验证移动有效性
        if (!Tools.isValidMove(begin, end)) {
            return false;
        }

        // 计算位置偏移量
        const deltaX = end.x - begin.x;
        const deltaY = end.y - begin.y;

        // 检查路径上的每个位置是否可通行
        if (deltaX !== 0) {
            // 水平移动
            const step = deltaX > 0 ? 1 : -1;
            for (let x = begin.x + step; x !== end.x; x += step) {
                const checkPos = { x: x, y: begin.y };

                // 对于中间路径位置，使用isPositionEmpty检查
                const result = Tools.isPositionEmpty(map, units, buildings, checkPos);
                if (!result.valid) {
                    return false; // 路径被阻挡
                }
            }
        } else if (deltaY !== 0) {
            // 垂直移动
            const step = deltaY > 0 ? 1 : -1;
            for (let y = begin.y + step; y !== end.y; y += step) {
                const checkPos = { x: begin.x, y: y };

                // 对于中间路径位置，使用isPositionEmpty检查
                const result = Tools.isPositionEmpty(map, units, buildings, checkPos);
                if (!result.valid) {
                    return false; // 路径被阻挡
                }
            }
        }

        // 检查目标位置是否可通行
        const targetPos = { x: end.x, y: end.y };
        const targetResult = Tools.isPositionEmpty(map, units, buildings, targetPos);
        if (!targetResult.valid) {
            return false; // 目标位置不可通行
        }

        return true;
    }
}
